﻿using Masuit.Tools;
using SimpleX.Sys;

namespace SimpleX.RBAC
{
    public class SysUserService : DbRepository<SysUser>, ISysUserService
    {
        private readonly ISysOrgService _sysOrgService;
        private readonly ICacheService _cacheService;
        private readonly IRelationService _relationService;
        private readonly IConfigService _configService;

        public SysUserService(ISysOrgService sysOrgService,
            ICacheService cacheService,
            IRelationService relationService,
            IConfigService configService)
        {
            _sysOrgService = sysOrgService;
            _cacheService = cacheService;
            _relationService = relationService;
            _configService = configService;
        }

        public async Task Add(UserAddInput input)
        {
            var check = await CheckInput(input);//检查参数
            if (check != "OK")
            {
                Unify.SetError(check);
                return;
            }
            var sysUser = input.Adapt<SysUser>();//实体转换
            if (string.IsNullOrWhiteSpace(sysUser.Password))
            {
                sysUser.Password = PwdUtils.DefaultPwd();//设置密码
            }
            sysUser.UserStatus = "Y";//默认状态
            sysUser.Avatar = "";

            await InsertAsync(sysUser);//添加数据
        }

        public async Task Delete(List<BaseIdInput> input)
        {
            var ids = input.Select(it => it.Id).ToList();
            if (ids.Count > 0)
            {
                foreach (var item in input)
                {
                    DeleteUserCache(item.Id);
                }

                var result = await itenant.UseTranAsync(async () =>
                {
                    //删除用户
                    await DeleteByIdsAsync(ids.Cast<object>().ToArray());
                    var relationRep = ChangeRepository<DbRepository<SysRelation>>();//切换仓储
                    //删除关系表
                    var delRelations = new List<string> { CateGoryConst.Relation_SYS_USER_HAS_MENU, CateGoryConst.Relation_SYS_USER_HAS_ROLE };
                    await relationRep.DeleteAsync(it => ids.Contains(it.ObjectId) && delRelations.Contains(it.Category));
                });
                if (result.IsSuccess)//如果成功了
                {
                }
                else
                {
                    throw result.ErrorException;
                }
            }
        }

        public async Task Edit(UserEditInput input)
        {
            await CheckInput(input);//检查参数
            var exist = await GetByIdAsync(input.Id);//获取用户信息
            if (exist != null)
            {
                var isSuperAdmin = exist.Account == "SuperAdmin";//判断是否有超管
                if (isSuperAdmin && !UserManager.SuperAdmin)
                {
                    Unify.SetError($"不可修改系统内置超管用户账号");
                    return;
                }

                var name = exist.Name;//姓名
                var sysUser = input.Adapt<SysUser>();//实体转换
                if (await Context.Updateable(sysUser).IgnoreColumns(it =>
                        new
                        {
                            //忽略更新字段
                            it.Password,
                            it.LastLoginIp,
                            it.LastLoginTime,
                        }).ExecuteCommandAsync() > 0)//修改数据
                {
                    //删除用户token缓存
                    DeleteUserCache(input.Id);
                }
            }
        }

        public async Task<SysUser> GetSysUserByAccount(string account)
        {
            var user = await GetFirstAsync(x => x.Account == account);
            //针对不忽略大小写的数据库再次进行强制验证大小写是否一致
            if (user?.Account != account)
            {
                return default;
            }
            return user;
        }

        public async Task<SysUser> GetSysUserById(string userId)
        {
            var user = await Context.Queryable<SysUser>()
                            .LeftJoin<SysOrg>((u, o) => u.OrgId == o.Id)
                            .Where(u => u.Id == userId)
                            .Select((u, o) => new SysUser
                            {
                                Id = u.Id.SelectAll(),
                                OrgName = o.Name,
                                OrgNames = o.Names
                            }).FirstAsync();
            return user;
        }

        public async Task SetLogined(string userId)
        {
            await Context.Updateable<SysUser>()
                .SetColumns(x => x.LastLoginTime == DateTime.Now)
                .Where(x => x.Id == userId)
                .ExecuteCommandAsync();
        }

        public async Task GrantRole(UserGrantRoleInput input)
        {
            var sysUser = await GetByIdAsync(input.Id);//获取用户信息
            if (sysUser != null)
            {
                if (sysUser.SuperAdmin == "Y")
                {
                    Unify.SetError($"不能给超管分配角色");
                    return;
                }
                //删除用户的接口缓存信息
                DeleteUserCache(input.Id);

                await _relationService.SaveRelationBatch(CateGoryConst.Relation_SYS_USER_HAS_ROLE, input.Id, input.RoleIdList.Select(it => it.ToString()).ToList(), null, true);
            }
        }

        public async Task<SqlSugarPagedList<SysUser>> Page(UserPageInput input)
        {
            var query = await GetQuery(input);//获取查询条件
            var pageInfo = await query.ToPagedListAsync(input.Current, input.Size);//分页
            return pageInfo;
        }

        public async Task<List<string>> OwnRole(BaseIdInput input)
        {
            var relations = await _relationService.GetRelationListByObjectIdAndCategory(input.Id, CateGoryConst.Relation_SYS_USER_HAS_ROLE);
            return relations.Select(it => it.TargetId).ToList();
        }

        public async Task<List<string>> OwnButtonCodeList()
        {
            if (UserManager.SuperAdmin)
            {
                var codes = await Context.Queryable<SysMenu>().Where(x => x.Category == CateGoryConst.Menu_BUTTON)
                                .Select(x => x.Code)
                                .ToListAsync();

                return codes;
            }
            else
            {
                var roleIds = await OwnRole(new BaseIdInput { Id = UserManager.UserId });

                //角色包含多少菜单
                var relations = await Context.Queryable<SysRelation>()
                                .InnerJoin<SysMenu>((x, y) => x.TargetId == y.Id)
                                .Where((x, y) => roleIds.Contains(x.ObjectId) && x.Category == CateGoryConst.Relation_SYS_ROLE_HAS_MENU)
                                .Select((x, y) => x)
                                .ToListAsync();

                //按钮Id
                var buttonIds = relations.SelectMany(x => x.ExtJson.ToObject<List<string>>()).Distinct();

                var codes = await Context.Queryable<SysMenu>().Where(x => x.Category == CateGoryConst.Menu_BUTTON && buttonIds.Contains(x.Id))
                                .Select(x => x.Code)
                                .ToListAsync();
                return codes;
            }
        }

        public async Task<List<string>> OwnPermissionCodeList()
        {
            //用户的包含的APIs
            var result = new List<string>();
            result = _cacheService.HashGetOne<List<string>>(CacheConst.Cache_UserRelation, CacheConst.Field_UserHasApi(UserManager.UserId));
            if (result != null && result.Count > 0)
            {
                return result;
            }
            result ??= [];

            var roleIds = await OwnRole(new BaseIdInput { Id = UserManager.UserId });

            //角色包含多少菜单
            var relations = await Context.Queryable<SysRelation>()
                            .InnerJoin<SysMenu>((x, y) => x.TargetId == y.Id)
                            .Where((x, y) => roleIds.Contains(x.ObjectId) && x.Category == CateGoryConst.Relation_SYS_ROLE_HAS_MENU)
                            .Select((x, y) => x)
                            .ToListAsync();

            //菜单Id + 按钮Id
            var menuIds = relations.Select(x => x.TargetId).ToList();
            var buttonIds = relations.SelectMany(x => x.ExtJson.ToObject<List<string>>());
            menuIds.AddRange(buttonIds);
            menuIds = menuIds.Distinct().ToList();

            //菜单对应的菜单和按钮
            var menus = await Context.Queryable<SysMenu>()
                             .Where(x => menuIds.Contains(x.Id))
                             .ToListAsync();

            foreach (var item in menus)
            {
                if (!string.IsNullOrEmpty(item.Apis))
                {
                    result.AddRange(item.Apis.Split(','));
                }
            }

            if (result.Count > 0)
                _cacheService.HashAdd(CacheConst.Cache_UserRelation, CacheConst.Field_UserHasApi(UserManager.UserId), result);

            return result;
        }

        public async Task DisableUser(BaseIdInput input)
        {
            var sysUser = await GetByIdAsync(input.Id);//获取用户信息
            if (sysUser != null)
            {
                var innerAdmin = sysUser.Account == "SuperAdmin";//判断是否有超管
                if (innerAdmin)
                {
                    Unify.SetError($"不可禁用系统内置超管用户账号");
                    return;
                }

                //删除用户的接口缓存信息
                DeleteUserCache(input.Id);

                await UpdateAsync(it => new SysUser
                {
                    UserStatus = "N",
                }, it => it.Id == input.Id);
            }
        }

        public async Task EnableUser(BaseIdInput input)
        {
            await UpdateAsync(it => new SysUser
            {
                UserStatus = "Y"
            }, it => it.Id == input.Id);
        }

        public async Task ResetPassword(BaseIdInput input)
        {
            DeleteUserCache(input.Id);
            var password = PwdUtils.DefaultPwd();
            var lastLoginTime = new DateTime(1996, 5, 21);
            await UpdateAsync(it => new SysUser
            {
                LastLoginTime = lastLoginTime,
                Password = password,
            }, it => it.Id == input.Id);
        }

        public async Task<dynamic> UpdatePassword(UpdatePasswordInput input)
        {
            //获取用户信息
            var oldPassword = PwdUtils.Decrypt(input.Password);
            var userInfo = await GetFirstAsync(x => x.Account == input.Account);
            if (userInfo == null)
                return Unify.SetError("原密码错误");

            var dbPassword = PwdUtils.Decrypt(userInfo.Password);
            if (dbPassword != oldPassword)
                return Unify.SetError("原密码错误");

            //通常来说，如果相似度高于80%左右，那么我们可以认为这两个密码相对较相似。
            var newPassword = PwdUtils.Decrypt(input.NewPassword);
            var similarity = PwdUtils.Similarity(dbPassword, newPassword);
            if (similarity > 80)
                return Unify.SetError($"新密码请勿与旧密码过于相似");

            if (!PwdUtils.IsValidPassword(newPassword))
                return Unify.SetError("新密码不符合规则，请包含至少一个大写字母、一个小写字母、一个数字和一个特殊字符，并且长度至少6个字符");

            userInfo.Password = input.NewPassword;
            userInfo.LastLoginTime = DateTime.Now;
            await Context.Updateable(userInfo).UpdateColumns(it => new { it.Password, it.LastLoginTime }).ExecuteCommandAsync();//修改密码

            return default;
        }

        public async Task<string> UpdateAvatar(BaseFileInput input)
        {
            var userInfo = await GetByIdAsync(UserManager.UserId);
            var file = input.File;
            using var fileStream = file.OpenReadStream();//获取文件流
            byte[] bytes = new byte[fileStream.Length];
            fileStream.Read(bytes, 0, bytes.Length);
            fileStream.Close();
            var base64String = Convert.ToBase64String(bytes);//转base64
            var avatar = "data:image/png;base64," + base64String;//转图片
            userInfo.Avatar = avatar;
            await Context.Updateable(userInfo).UpdateColumns(it => new { it.Avatar }).ExecuteCommandAsync();//修改密码
            return avatar;
        }

        public async Task<dynamic> UpdateUserInfo(UpdateInfoInput input)
        {
            //如果手机号不是空
            if (!string.IsNullOrEmpty(input.Phone))
            {
                if (!input.Phone.MatchPhoneNumber())//判断是否是手机号格式
                    return Unify.SetError($"手机号码格式错误");
                var any = await IsAnyAsync(it => it.Phone == input.Phone && it.Id != UserManager.UserId);//判断是否有重复的
                if (any)
                    return Unify.SetError($"系统已存在该手机号");
            }
            if (!string.IsNullOrEmpty(input.Email))
            {
                var match = input.Email.MatchEmail();
                if (!match.isMatch)
                    return Unify.SetError($"邮箱格式错误");

                var any = await IsAnyAsync(it => it.Email == input.Email && it.Id != UserManager.UserId);//判断是否有重复的
                if (any)
                    return Unify.SetError($"系统已存在该邮箱");
            }

            //更新指定字段
            var result = await UpdateAsync(it => new SysUser
            {
                Email = input.Email,
                Phone = input.Phone,
            }, it => it.Id == UserManager.UserId);

            return default;
        }

        public void DeleteUserCache(string userId)
        {
            //用户角色信息
            _cacheService.HashDel<List<string>>(CacheConst.Cache_UserRelation, CacheConst.Field_UserHasApi(UserManager.UserId));
            _cacheService.HashDel<List<string>>(CacheConst.Cache_UserRelation, CacheConst.Field_UserHasMenu(UserManager.UserId));

            //用户Token信息
            foreach (var item in LoginDevices.AllowDevices)
            {
                var key = CacheConst.Cache_UserToken + userId + ":" + item;
                _cacheService.Remove(key);
            }
        }

        public async Task UpdateWorkbench(UpdateWorkbenchInput input)
        {
            //关系表保存个人工作台
            await _relationService.SaveRelation(CateGoryConst.Relation_SYS_USER_WORKBENCH_DATA, UserManager.UserId, null, input.WorkbenchData, true);
        }

        public async Task<string> GetLoginWorkbench()
        {
            //获取个人工作台信息
            var repo = ChangeRepository<DbRepository<SysRelation>>();
            var sysRelation = await repo.GetFirstAsync(x => x.Category == CateGoryConst.Relation_SYS_USER_WORKBENCH_DATA && x.ObjectId == UserManager.UserId);
            if (sysRelation != null)
            {
                //如果有数据直接返回个人工作台
                return sysRelation.ExtJson.ToLower();
            }
            else
            {
                //如果没数据去系统配置里取默认的工作台
                var devConfig = await _configService.GetByConfigKey(CateGoryConst.Config_SYS_BASE, "SYS_DEFAULT_WORKBENCH_DATA");
                if (devConfig != null)
                {
                    return devConfig.ConfigValue.ToLower();//返回工作台信息
                }
                else
                {
                    return "";
                }
            }
        }

        #region 私有方法

        private async Task<string> CheckInput(SysUser sysUser)
        {
            //判断账号重复,直接从redis拿
            var user = await GetFirstAsync(x => x.Account == sysUser.Account);
            if (user != null && user.Id != sysUser.Id)
                return ($"存在重复的账号:{sysUser.Account}");

            //如果手机号不是空
            if (!string.IsNullOrEmpty(sysUser.Phone))
            {
                if (!sysUser.Phone.MatchPhoneNumber())//验证手机格式
                    return ($"手机号码：{sysUser.Phone} 格式错误");
            }
            //如果邮箱不是空
            if (!string.IsNullOrEmpty(sysUser.Email))
            {
                var (ismatch, match) = sysUser.Email.MatchEmail();//验证邮箱格式
                if (!ismatch)
                    return ($"邮箱：{sysUser.Email} 格式错误");
            }
            return "OK";
        }

        private async Task<ISugarQueryable<SysUser>> GetQuery(UserPageInput input)
        {
            var searchkeys = input.SearchKey?.Split(',');

            var orgIds = await _sysOrgService.GetOrgChildIds(input.OrgId);//获取下级机构
            var query = Context.Queryable<SysUser>()
                .LeftJoin<SysOrg>((u, o) => u.OrgId == o.Id)
                .WhereIF(!string.IsNullOrEmpty(input.OrgId), u => orgIds.Contains(u.OrgId))//根据组织
                .WhereIF(input.Expression != null, input.Expression?.ToExpression())//动态查询
                .WhereIF(!string.IsNullOrEmpty(input.UserStatus), u => u.UserStatus == input.UserStatus)//根据状态查询
                .WhereIF(!string.IsNullOrEmpty(input.SearchKey), u => searchkeys.Contains(u.Name) || searchkeys.Contains(u.Account))//根据关键字查询
                .OrderByIF(!string.IsNullOrEmpty(input.SortField), $"u.{input.SortField} {input.SortOrder}")
                .OrderBy(u => u.Id)//排序
                .Select((u, o) => new SysUser
                {
                    Id = u.Id.SelectAll(),
                    OrgName = o.Name,
                    OrgNames = o.Names
                })
                .Mapper(u =>
                {
                    u.Password = null;//密码清空
                });
            return query;
        }

        #endregion
    }
}